using System;
using System.Collections;
using System.Drawing;
using System.Globalization;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using SHDocVw;
using mshtml;
using System.IO;
using System.Collections.Generic;

////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Dimok.IE
//
// summary:	.
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Dimok.IE{

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Ie. </summary>
	///
	/// <remarks>	Dimon, 12/21/2010. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public class IE : MarshalByRefObject{
		public IE PopUp;
		public bool HasPopUp{get{return PopUp != null && PopUp.ie != null;}}
		public InternetExplorer ie;
		protected InternetExplorerClass ieClass{get{try{return (InternetExplorerClass)ie;}catch{return null;}}}
		protected static string defaultUrl = "about:blank";
		public int WaitTimeOut = 10*1000; // 10 seconds
		protected Regex Title = null;

		public static IE FindIE(string name){
			foreach(SHDocVw.InternetExplorer br in new SHDocVw.ShellWindows() )
				if( ((HTMLDocument)br.Document).title == name )return new IE(br);
			return null;
		}
		#region Constructor
		private IE(InternetExplorer ie){this.ie = ie;}
		public IE(Regex title):this(){Title = title;}
		public IE():this(defaultUrl){}
		public IE(string url):this(url,true){}
		public IE(string url,bool visible){
			if( (url+"") == "" )url = defaultUrl;
			Init(visible,url);
		}
		~IE(){Destroy();}

		public void Init(){Init(defaultUrl);}
		//public void Init(bool visible){Init(visible,defaultUrl);}
		public void Init(string url){Init(true,url);}
		/// <summary>
		/// Initializes IE instance
		/// </summary>
		/// <param name="visible">true</param>
		/// <param name="url">about:blank</param>
		public void Init(bool visible,string url){
			Destroy();
			GC.Collect();
			InternetExplorer browser = Title == null ? null : GetBrowserWindowByTitle(Title);
			//ie = browser != null ? browser : (InternetExplorer)System.Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application",true));//new InternetExplorerClass();
			ie = browser != null ? browser : new InternetExplorerClass();

			ie.Visible = visible;
			ie.Silent = true;
			if( ieClass != null){
				DoEventsAndWait(500);
				try{
					ieClass.NewWindow +=new DWebBrowserEvents_NewWindowEventHandler(ie_NewWindow);
				}catch{
					DoEventsAndWait(10000);
					ieClass.NewWindow +=new DWebBrowserEvents_NewWindowEventHandler(ie_NewWindow);
				}
			}
			//ie.NewWindow2 +=new DWebBrowserEvents2_NewWindow2EventHandler(ie_NewWindow2);
			ie.NavigateComplete2 +=new DWebBrowserEvents2_NavigateComplete2EventHandler(ie_NavigateComplete2);
			//ie.FrameNewWindow +=new DWebBrowserEvents_FrameNewWindowEventHandler(ie_FrameNewWindow);
			if( url != null )Navigate(url);
		}
		public void Destroy(){
			try{
				ie.Quit();
				ie = null;
			}catch{}
		}
		#endregion

		[StructLayout(LayoutKind.Sequential)]
		private struct Win32MSG {
			public IntPtr WindowHandle;
			public int Message;
			public IntPtr WParam;
			public IntPtr LParam;
			public uint Time;
			public Point Point;
		}
		[System.Security.SuppressUnmanagedCodeSecurity]
		[DllImport("user32.dll")]
		private static extern int PeekMessage(out Win32MSG Message,
				IntPtr windowHandle, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg);

		[System.Security.SuppressUnmanagedCodeSecurity]
		[DllImport("user32.dll")]
		private static extern int TranslateMessage(ref Win32MSG Message);

		[System.Security.SuppressUnmanagedCodeSecurity]
		[DllImport("user32.dll")]
		private static extern int DispatchMessage(ref Win32MSG Message);

		public static bool ProcessMessage() {
			while (true) {

				Win32MSG msg = new Win32MSG();
				int ret = PeekMessage(out msg, Application.OpenForms[0].Handle, 0, 0, 1);
				if (ret < 0) {
					throw new Exception();
				} else if (ret == 0) {
					return true;
				}
				TranslateMessage(ref msg);
				DispatchMessage(ref msg);
			}
		}

		static Form OpenForm { get { return Application.OpenForms.Count==0?(Form)null: Application.OpenForms[0]; } }
		delegate void DoEventsHandler();
		static void DoEvents_Safe() {
			Thread.CurrentThread.Priority = ThreadPriority.Lowest;
				Application.DoEvents();
			//ProcessMessage();
			Thread.Sleep(100);
		}
		public static void DoEvents() {
			if (OpenForm != null && OpenForm.Controls.Count>0 && OpenForm.Controls[0].InvokeRequired) {
				IAsyncResult aRes = OpenForm.Controls[0].BeginInvoke(new DoEventsHandler(DoEvents_Safe));
				aRes.AsyncWaitHandle.WaitOne();
				OpenForm.Controls[0].EndInvoke(aRes);
			} else
				Application.DoEvents();
		}

		#region Navigation
		public bool NavigationDone = true;
		public bool Visible{ get{return ie.Visible;} set{ie.Visible = value;} }
		public void Focus(){ doc.focus(); }
		public void Stop(){ ie.Stop(); }
		public void GoBack(){ ie.GoBack(); }
		public void Navigate(){Navigate(defaultUrl,true);}
		public void Navigate(string url){Navigate(url,true);}
		public void Navigate(string url,bool wait){
			if( ie == null )Init(true,null);
			object n = null;
			try{
				ie.Stop();
				NavigationDone = true;
				ie.Navigate(url,ref n,ref n,ref n,ref n);
			}catch(System.Runtime.InteropServices.COMException exc){
				Init(true,null);
				NavigationDone = false;
				ie.Navigate(url,ref n,ref n,ref n,ref n);
			}
			try{
				if( wait )WaitIE();
			}catch(Exception){
				WaitIE();
			}
		}
		public void WaitForDoc(string url){
			WaitIE();
			return;
			try{
				while (!this.doc.url.ToLower().EndsWith(url.ToLower()))
					/*Application.*/DoEvents();
				//IHTMLElementCollection images = this.doc.images;
				//foreach( HTMLImg img in images )
				//	img.src = "";
			}catch{
				/*Application.*/DoEvents();
			}
		}
		//public void WaitWhileBusy(){
		//  while( ie.Busy ){
		//    Application.DoEvents();
		//    Application.DoEvents();
		//    Application.DoEvents();
		//  }
		//}
		public static void DoEventsAndWait(int milliseconds){
			long ticks = DateTime.Now.AddMilliseconds(milliseconds).Ticks;
			int i = 0;
			while( ticks > DateTime.Now.Ticks ){
				/*Application.*/DoEvents();
				i++;
			}
			return;
		}
		public void WaitIE(bool navigationDone){
			NavigationDone = navigationDone;
			WaitIE();
		}
		public void WaitIE(){WaitIE(doc);}
		public void WaitIE(HTMLDocument doc){
			WaitIE(doc,WaitTimeOut);
		}
		public void WaitIE(int timeOut){WaitIE(doc,timeOut);}
		public void WaitIE(HTMLDocument doc,int timeOut){
			DateTime end = DateTime.Now.AddMilliseconds(timeOut);
			//bool noImages = false;
			while( DateTime.Now < end ){
				try{DoEventsAndWait(5);}catch{}
				if( !NavigationDone )continue;
				try{
					/*
					if( false && !noImages ){
						IHTMLElementCollection images = doc.images;
						foreach( HTMLImg img in images ){
							img.src = "";
							noImages = true;
						}
					}
					FramesCollection frames = (FramesCollection)doc.frames;
					if( frames.length > 0 )Application.DoEvents();
					for( int i = 0; i < frames.length; i++ ){
						object o = i;
						HTMLWindow2Class frame = (HTMLWindow2Class)frames.item(ref o);
						frame.open("about:blank","_self","",true);
					}
					*/
					if( doc == null || doc.readyState !=	"complete" )continue;
					try{
						for( int w = 0; w < doc.frames.length; w++ )
							WaitIE(Document(doc.parentWindow,w),timeOut);
					}catch(InvalidCastException){}
					if( (int)ie.ReadyState == 4 )return;
					break;
				}catch( Exception exc ){
					exc = null;
				}
			}
			//if( DateTime.Now >= end )throw new Exception("Got stuck!");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a value indicating whether the busy. </summary>
		///
		/// <value>	true if busy, false if not. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private bool Busy{
			get{
				if( ie.Busy || doc.body == null )return true;
				foreach( object obj in doc.all ){
					try{
						IHTMLElement2 el2 = ( IHTMLElement2)obj;
						if( el2.readyStateValue != 4 )
							try{
								if( !(((IHTMLElement)el2).tagName.ToUpper() == "IMG") )return true;
							}catch{}
					}catch(Exception exc){
						string s = exc.Message;
					}
				}
				return false;
			}
		}
		#endregion

		#region GoToLink

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Go to link by h reference. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="href">		The href. </param>
		/// <param name="assert">	true to assert. </param>
		///
		/// <returns>	true if it succeeds, false if it fails. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public bool GoToLinkByHRef(string href,bool assert){return GoToLinkByAttr("href",href,assert);}
		// public bool GoToLinkByText(string text,bool assert){return GoToLinkByAttr("innerText",text,
		// assert);} 
		public bool GoToLinkByAttr(string attrName,string attrValue,bool assert){
			try{
				GoToLink(GetElementByAttr(attrName,attrValue));
				return true;
			}catch(HTMLElementNotFoundException){
				WaitIE();
				if( assert )throw;
				return false;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Go to link by text. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="innerText">	The inner text. </param>
		/// <param name="assert">			true to assert. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void GoToLinkByText( string innerText, bool assert) {
			GoToLinkByText(doc.documentElement,innerText,assert);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Go to link by text. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="HTMLElementNotFoundException">	Thrown when htmlelementnotfound. </exception>
		///
		/// <param name="parent">			The parent. </param>
		/// <param name="innerText">	The inner text. </param>
		/// <param name="assert">			true to assert. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void GoToLinkByText(IHTMLElement parent, string innerText, bool assert) {
			try {
				GoToLink(GetElementByText(parent, "A", innerText));
			} catch (HTMLElementNotFoundException) {
				WaitIE();
				if (assert) throw;
			}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Go to link. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="link">	The link. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void GoToLink(IHTMLElement link){
			link.click();
			WaitIE();
		}
		#endregion

		#region Doc/Window

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the document class. </summary>
		///
		/// <value>	The document class. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public HTMLDocument docClass{get{return (HTMLDocument)ie.Document;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets the document. </summary>
		///
		/// <value>	The document. </value>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public HTMLDocument doc{get{return (HTMLDocument)ie.Document;}}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Documents. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public HTMLDocument Document(params int[] frames){return Document(doc,frames);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Documents. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">		The document. </param>
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static HTMLDocument Document(HTMLDocument doc,params int[] frames){
			HTMLDocument document = null;
			foreach( int frame in frames )
				document = Document(document==null?doc:document,(object)frame);
			return document;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Documents. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">		The document. </param>
		/// <param name="frame">	The frame. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static HTMLDocument Document(HTMLDocument doc,object frame){
			IHTMLWindow2 w = Frame(doc.frames,frame);
			return w == null ? null : (HTMLDocument)w.document;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Documents. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="window">	The window. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static HTMLDocument Document(IHTMLWindow2 window){return (HTMLDocument)window.document;}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Documents. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="window">	The window. </param>
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static HTMLDocument Document(IHTMLWindow2 window,params int[] frames){
			return (HTMLDocument)Frame(window,frames).document;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Frames. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public IHTMLWindow2 Frame(params int[] frames){return Frame(doc.parentWindow,frames);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Frames. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="window">	The window. </param>
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLWindow2 Frame(IHTMLWindow2 window,params int[] frames){
			IHTMLWindow2 frame = null;
			foreach( int f in frames )
				frame = Frame(frame==null?window:frame,(object)f);
			return frame;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Frames. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="document">	The document. </param>
		/// <param name="frame">		The frame. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLWindow2 Frame(HTMLDocument document,object frame){
			return Frame(document.frames,frame);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Frames. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="window">	The window. </param>
		/// <param name="frame">	The frame. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLWindow2 Frame(IHTMLWindow2 window,object frame){
			return Frame(window.frames,frame);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Frames. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="frames">	A variable-length parameters list containing frames. </param>
		/// <param name="frame">	The frame. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLWindow2 Frame(FramesCollection frames,object frame){
			if( (int)frame >= frames.length )return null;
			return (IHTMLWindow2)frames.item(ref frame);
		}
		#endregion

		#region MSHTML

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Searches for the first parent by tag. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="HTMLElementNotFoundException">	Thrown when htmlelementnotfound. </exception>
		///
		/// <param name="child">			The child. </param>
		/// <param name="tagName">		Name of the tag. </param>
		/// <param name="returnNull">	true to return null. </param>
		///
		/// <returns>	The found parent by tag. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement FindParentByTag(IHTMLElement child,string tagName,bool returnNull){
			tagName = tagName.ToLower();
			while( child != null && child.tagName.ToLower() != tagName )
				child = child.parentElement;
			if( child == null && !returnNull )
				throw new HTMLElementNotFoundException("Parent <"+tagName+"> not found.");
			return child;
		}

			#region Get Element By

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by text. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="tagName">	Name of the tag. </param>
		/// <param name="text">			The text. </param>
		///
		/// <returns>	The element by text. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public IHTMLElement GetElementByText(string tagName,string text){
			return GetElementByText(doc,tagName,text);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by text. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">			The document. </param>
		/// <param name="tagName">	Name of the tag. </param>
		/// <param name="text">			The text. </param>
		///
		/// <returns>	The element by text. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByText(HTMLDocument doc,string tagName,string text){
			return GetElementByText(doc.documentElement,tagName,text);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by text. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="Exception">										Thrown when exception. </exception>
		/// <exception cref="HTMLElementNotFoundException">	Thrown when htmlelementnotfound. </exception>
		///
		/// <param name="parent">		The parent. </param>
		/// <param name="tagName">	Name of the tag. </param>
		/// <param name="text">			The text. </param>
		///
		/// <returns>	The element by text. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByText(IHTMLElement parent,string tagName,string text){
			foreach( IHTMLElement el in Tags(parent,tagName) )
				try{
					if( el.innerText != null && Regex.IsMatch(el.innerText,text,RegexOptions.IgnoreCase) )
						try{
							return GetElementByText(el,tagName,text);
						}catch(HTMLElementNotFoundException){
							return el;
						}
				}catch(Exception exc){
					throw new Exception("Tag <"+tagName+">"+text+" ...</"+tagName+">\n",exc);
				}
			throw new HTMLElementNotFoundException("Tag <"+tagName+">"+text+" ...</"+tagName+"> not found.");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="name">	The name. </param>
		/// <param name="type">	The type. </param>
		///
		/// <returns>	The element by name. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public IHTMLElement GetElementByName(string name,string type){
			return GetElementByName(doc,name,type);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">	The document. </param>
		/// <param name="name">	The name. </param>
		/// <param name="type">	The type. </param>
		///
		/// <returns>	The element by name. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByName(HTMLDocument doc,string name,string type){
			foreach( IHTMLInputElement el in doc.getElementsByName(name) )
				if( el.type.ToLower() == type.ToLower() )return (IHTMLElement)el;
			return null;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by attribute. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="attrName">		Name of the attribute. </param>
		/// <param name="attrValue">	The attribute value. </param>
		///
		/// <returns>	The element by attribute. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public IHTMLElement GetElementByAttr(string attrName,string attrValue){
			return GetElementByAttr(doc,attrName,attrValue);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by attribute. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">				The document. </param>
		/// <param name="attrName">		Name of the attribute. </param>
		/// <param name="attrValue">	The attribute value. </param>
		///
		/// <returns>	The element by attribute. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByAttr(HTMLDocument doc,string attrName,string attrValue){
			return GetElementByAttr(doc.documentElement,attrName,attrValue);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by attribute. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="HTMLElementNotFoundException">	Thrown when htmlelementnotfound. </exception>
		///
		/// <param name="parent">			The parent. </param>
		/// <param name="attrName">		Name of the attribute. </param>
		/// <param name="attrValue">	The attribute value. </param>
		///
		/// <returns>	The element by attribute. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByAttr(IHTMLElement parent,string attrName,string attrValue){
			Debug.WriteLine("Attribute:"+attrValue);
			foreach( IHTMLElement el in (IHTMLElementCollection)parent.all ){
				Debug.WriteLine(el.getAttribute(attrName,0));
				if( el.getAttribute(attrName,0) != null &&
					Regex.IsMatch(el.getAttribute(attrName,0)+"",attrValue,RegexOptions.IgnoreCase) )
					return el;
			}
			throw new HTMLElementNotFoundException("<TAG "+attrName+"='"+attrValue+"'>...</TAG> not found.");
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="name">	The name. </param>
		///
		/// <returns>	The element by name. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public IHTMLElement GetElementByName(string name){return GetElementByName(doc,name);}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">	The document. </param>
		/// <param name="name">	The name. </param>
		///
		/// <returns>	The element by name. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement GetElementByName(HTMLDocument doc,string name){
			return (IHTMLElement)doc.getElementsByName(name).item(0,0);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="elementName">	Name of the element. </param>
		/// <param name="elementValue">	The element value. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public object SetElementValue(string elementName,object elementValue){
			return SetElementValue(doc,elementName,elementValue);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">					The document. </param>
		/// <param name="elementName">	Name of the element. </param>
		/// <param name="elementValue">	The element value. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static object SetElementValue(HTMLDocument doc,string elementName,object elementValue){
			return SetElementValue(GetElementByName(doc,elementName),elementValue);
		}
			#endregion

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Removes the child described by element. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="element">	The element. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static IHTMLElement RemoveChild(IHTMLElement element) {
			if (element == null) return null;
			return (element as IHTMLDOMNode).parentNode.removeChild(element as IHTMLDOMNode) as IHTMLElement;
		}

			#region Get/Set Element value

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="form">		The form. </param>
		/// <param name="name">		The name. </param>
		/// <param name="Value">	The value. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static object SetElementValue(IHTMLFormElement form,string name,object Value){
			IEnumerator en = form.GetEnumerator();
			while( en.MoveNext() )
				if( ((HTMLInputElement)en.Current).name == name )
					return SetElementValue((IHTMLElement)en.Current,Value);
			return null;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NotSelectedException">	Thrown when notselected. </exception>
		/// <exception cref="ApplicationException">	Thrown when application. </exception>
		///
		/// <param name="element">			The element. </param>
		/// <param name="elementValue">	The element value. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static object SetElementValue(IHTMLElement element,object elementValue){
			HTMLDocument doc = (HTMLDocument)element.document;
			if( elementValue == DBNull.Value )return null;
			if( element.tagName == "SELECT" ){
				IHTMLSelectElement select = (IHTMLSelectElement)element;
				if( elementValue.GetType() == typeof(int) )
					return select.selectedIndex = (int)elementValue;
				if( elementValue.GetType() == typeof(double) ){
					Double dblValue;
					foreach( IHTMLOptionElement option in (IHTMLSelectElement)element )
						if( Double.TryParse(option.value,NumberStyles.Float,CultureInfo.CurrentCulture.NumberFormat,out dblValue) && dblValue == (Double)elementValue ){
							option.selected = true;
							return elementValue;
						}
					throw new NotSelectedException(select.name,elementValue);
				}							
				select.value = elementValue.ToString();
				if( select.selectedIndex == -1 )
					throw new NotSelectedException(select.name,elementValue);
				return elementValue;
			}
			IHTMLInputElement input = (IHTMLInputElement)element;
			switch( input.type ){
				case "text": goto case "hidden";
				case "password": goto case "hidden";
				case "hidden":
					input.value = elementValue.ToString(); break;
				case "checkbox":
					input.@checked = (bool)elementValue; break;
				case "button": 
					MessageBox.Show("<button> type is not implemented!");
					break;
				case "submit": 
					MessageBox.Show("<submit> type is not implemented!");
					break;
				case "reset": 
					MessageBox.Show("<reset> type is not implemented!");
					break;
				case "radio": 
					SetRadioButtonValue(doc,input.name,elementValue); break;
				default:
					throw new ApplicationException("Unknown input type: "+input.type);
			}
			try{
				((IHTMLElement2)input).focus();
				((IHTMLElement2)input).blur();
			}catch{};
			return elementValue;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets a radio button value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="elementName">	Name of the element. </param>
		/// <param name="elementValue">	The element value. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected void SetRadioButtonValue(string elementName,object elementValue){
			SetRadioButtonValue(doc,elementName,elementValue);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets a radio button value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="doc">					The document. </param>
		/// <param name="elementName">	Name of the element. </param>
		/// <param name="elementValue">	The element value. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		protected static void SetRadioButtonValue(HTMLDocument doc,string elementName,object elementValue){
			IHTMLElementCollection rads = doc.getElementsByName(elementName);
			foreach( IHTMLInputElement rad in rads )
				if( rad.value == elementValue.ToString() ){rad.@checked = true;return;}
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="elementName">	Name of the element. </param>
		///
		/// <returns>	The element value. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public string GetElementValue(string elementName){
			return GetElementValue(GetElementByName(elementName)).ToString();
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets an element value. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="ApplicationException">	Thrown when application. </exception>
		///
		/// <param name="element">	The element. </param>
		///
		/// <returns>	The element value. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public object GetElementValue(IHTMLElement element){
			object ret = null;
			if( element.tagName == "SELECT" )
				return ((IHTMLSelectElement)element).selectedIndex;
			IHTMLInputElement input = (IHTMLInputElement)element;
			switch( input.type ){
				case "text":
					ret = input.value; break;
				case "hidden":
					ret = input.value; break;
				case "checkbox":
					ret  = input.@checked;	break;
				case "button": break;
				case "submit": break;
				case "reset": break;
				case "radio": break;
				default:
					throw new ApplicationException("Unknown input type: "+input.type);
			}
			return ret;
		}
			#endregion
		
		#endregion MSHTML

		#region Helpers

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Inject base. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="html">	The html. </param>
		/// <param name="href">	The href. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static string InjectBASE(string html, string href) { return Regex.Replace(html, "<head[^>]*>", "<HEAD><BASE href=\"" + href + "\">", RegexOptions.IgnoreCase | RegexOptions.Compiled); }

		// public static IHTMLElementCollection Tags(IHTMLElement parent, string tagName) {
		// 	IHTMLElementCollection all = (IHTMLElementCollection)parent.all;
		// 	return (IHTMLElementCollection)all.tags(tagName);
		// } 

		public static mshtml.IHTMLElementCollection Tags(mshtml.IHTMLElement el, string tagName) {
			mshtml.IHTMLElementCollection all = (mshtml.IHTMLElementCollection)el.all;
			return all.tags(tagName) as mshtml.IHTMLElementCollection;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Tags. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="el">				The el. </param>
		/// <param name="tagName">	Name of the tag. </param>
		///
		/// <returns>	. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static mshtml.IHTMLElement Tag(mshtml.IHTMLElement el, string tagName) {
			mshtml.IHTMLElementCollection tags = Tags(el, tagName);
			return tags.length == 0 ? (mshtml.IHTMLElement)null : tags.item(0, 0) as mshtml.IHTMLElement;
		}
		#endregion Helpers

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Ie navigate complete 2. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="pDisp">	The disp. </param>
		/// <param name="URL">		[in,out] URL of the document. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private void ie_NavigateComplete2(object pDisp, ref object URL) {
			NavigationDone = true;
		}

		System.Threading.Timer popUpTimer;
		public string NewUrl = "";
		public string NewPopUpName = "";

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Ie new window. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="URL">							URL of the document. </param>
		/// <param name="Flags">						The flags. </param>
		/// <param name="TargetFrameName">	Name of the target frame. </param>
		/// <param name="PostData">					[in,out] Information describing the post. </param>
		/// <param name="Headers">					The headers. </param>
		/// <param name="Processed">				[in,out] The processed. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private void ie_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed) {
			NewUrl = URL;
			NewPopUpName = TargetFrameName;
			InternetExplorer iePopUp = GetPopUpByURL(URL);
			if (iePopUp != null) {
				PopUp = new IE(iePopUp);
				PopUp.WaitIE();
			}else
				popUpTimer = new System.Threading.Timer(new TimerCallback(SetPopUpByURL), TargetFrameName, 100, 0);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets a pop up by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <exception cref="NotImplementedException">	Thrown when the requested operation is
		/// 																						unimplemented. </exception>
		///
		/// <param name="name">	The name. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void SetPopUpByName(object name) {
			throw new NotImplementedException();
			//PopUp = new IE(GetPopUpByName(name + ""));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Sets a pop up by url. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="url">	about:blank. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public void SetPopUpByURL(object url) {
			PopUp = new IE(GetPopUpByURL(url + ""));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a pop up by name. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="name">	The name. </param>
		///
		/// <returns>	The pop up by name. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		[Obsolete("Need to figure out how to get a reference to ie.Document.parentWindow.",true)]
		public static InternetExplorer GetPopUpByName(string name) {
			foreach (InternetExplorer ie in new ShellWindows())
				try {
					HTMLDocument d = ie.Document as HTMLDocument;
					if ( d != null && d.parentWindow.name == name) return ie;
				} catch { }
			return null;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a pop up by url. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="url">	about:blank. </param>
		///
		/// <returns>	The pop up by url. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static InternetExplorer GetPopUpByURL(string url) {
			foreach (InternetExplorer ie in new ShellWindows()) {
				if (ie.LocationURL == url) return ie;
			}
			return null;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a browser window by title. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="titlePattern">	The title pattern. </param>
		///
		/// <returns>	The browser window by title. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static InternetExplorer GetBrowserWindowByTitle(string titlePattern) {
			return GetBrowserWindowByTitle(new Regex(titlePattern,RegexOptions.IgnoreCase));
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Gets a browser window by title. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="title">	The title. </param>
		///
		/// <returns>	The browser window by title. </returns>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		public static InternetExplorer GetBrowserWindowByTitle(Regex title){
			var l = new List<string>();
			foreach(InternetExplorer ie in new ShellWindows())
				try {
					var t = ((HTMLDocument)ie.Document).title;
					l.Add(t);
					if (title.IsMatch(t))
						return ie;
				} catch (Exception exc) { Log(string.Join(Environment.NewLine, l.ToArray()) + Environment.NewLine + exc + ""); }
			Log(string.Join(Environment.NewLine, l.ToArray())); 
			return null;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Logs. </summary>
		///
		/// <remarks>	Dimon, 12/21/2010. </remarks>
		///
		/// <param name="s">	The string. </param>
		////////////////////////////////////////////////////////////////////////////////////////////////////

		private static void Log(string s) {
			var sw = System.IO.File.CreateText(Path.Combine(Environment.CurrentDirectory, "Exceptons.txt"));
			sw.Write(s);
			sw.Close();
		}
	}
}
